An exception is an event in which the execution of a particular macroinstruction by a microprocessor requires special handling. When an exception occurs, the microprocessor alters the normal program flow to report or correct the condition causing the exception. This is normally done by invoking an appropriate exception service routine.
Exceptions are generally classified as faults, traps or aborts, depending upon the way the event is reported, and whether or not the instruction causing the exception can be restarted or re-executed by the microprocessor. Faults are exceptions that are detected and serviced before the execution of the faulting instruction. Traps are exceptions that are reported immediately after the execution of the instruction which causes the exception. Aborts are exceptions which do not permit the precise location of the instruction causing the exception to be determined.
Microprocessors commonly contain logic for performing a variety of exception checks on addresses generated by the microprocessor (hereinafter "address-exception" checks). Three types of address-exception checks are of particular importance to the present invention. The first is an address limit check. Address limit checks are typically performed by microprocessors that use segmentation. The purpose of the address limit check is to prevent a program from accessing memory outside a given variable-size segment. To perform the address limit check, the microprocessor compares each generated memory address to the addresses representing the upper and lower boundaries of the appropriate segment. The upper and lower segment boundaries are specified by internal registers which are typically loaded by the operating system. If an instruction attempts to access memory outside of the designated segment, the microprocessor generates a limit error exception. Limit errors are generally treated as either traps or faults.
The second type of exception check is a page fault check. This type of exception occurs with microprocessors having paging capabilities whenever the microprocessor references a page which is not present in memory. Upon the occurrence of a page fault, the microprocessor invokes the appropriate service routine which loads the necessary page into memory. The microprocessor then restarts the instruction which caused the fault.
The third type of exception check of importance to the present invention is a breakpoint check. A breakpoint is a type of exception that can be intentionally generated upon the occurrence of a predetermined event, for the purpose of facilitating program or hardware debugging. Upon the occurrence of the event, an exception service routine is taken which allows the debugger to examine the contents of internal registers.
One type of event which can be used to generate breakpoint exceptions is the generation of predetermined addresses for accessing either code or data. For example, the microprocessor can be set up to generate a breakpoint exception whenever an instruction located at a specified address is executed, or when operand data is written to a specified address. Breakpoints resulting from instruction fetches are typically taken as faults (i.e., before the instruction is executed), and breakpoints resulting from operand accesses are typically taken as traps (i.e., after the data transfer takes place).
In order to properly handle limit error, page fault and breakpoint exceptions, the microprocessor must be able to identify the instruction causing the exception, and prevent subsequent instructions from being executed before taking the exception. For page faults and limit errors, the microprocessor must also halt the execution of the exception-causing instruction. If the exception-causing instruction and subsequent instructions are not halted before taking the exception, the state of the machine or memory may change. For example, if a limit error is not immediately handled, a memory location outside of a data segment may be overwritten, corrupting necessary data. Or, if a breakpoint exception is not immediately taken, registers internal to the microprocessor may change after a breakpoint event occurs, making it difficult for the debugger to isolate a problem.
The task of tracking the exception-causing instruction and preventing the execution of subsequent instructions becomes complex when the microprocessor uses a high degree of pipelining, or when the microprocessor has the capability of executing instructions in parallel. Once it has been determined that an instruction in the pipeline will cause an exception, one or more subsequent instructions will typically have already entered the pipelines, and the program counter will point to some instruction other than the exception-causing instruction.
As a result, microprocessors commonly reduce pipelining and/or parallel instruction execution when certain types of address-exception checks are enabled. For example, microprocessors in the .times.86 family are normally designed to reduce pipelining and/or parallel instruction execution whenever breakpoints are enabled. Although this technique allows the microprocessor to take the exception at the correct time, it has the disadvantage of slowing down the rate of program execution. In the case of breakpoints, it is undesirable to slow down program execution, especially when the program debugger is attempting to debug a time-dependent bug.
The present invention is concerned with the problem of ensuring that address-exceptions are taken at the correct time, without a change in the state of the machine or memory. For purposes of describing the present invention, the following terminology will be used. The term "fetch" will refer to the reading of code (i.e, instructions) from memory. "Operand" will refer to memory accesses involving non-code data. "Fetch-exception" will refer to an exception resulting from a fetch from a specific address or range of addresses. "Operand-exception" will refer to an exception resulting from an operand access. "Take" or "generate," when referring to an exception, will refer to the process of causing an exception service routine to be entered. "Detect," when referring to an exception, will refer to the process of checking for exception-causing events, the detection of which may or may not result in the generation of an exception. "Instruction" will refer to a macroinstruction which is part of the instruction set of the subject microprocessor.